import {bytesToInt, intToBytes} from "@lodestar/utils";
import {BUCKET_LENGTH} from "./const.js";

export const uintLen = 8;

/**
 * Encode a key for the db write/read, Prepend a bucket to a key
 *
 * The encoding of key is very important step that can cause failure of proper indexing and querying of data
 *
 * We are using LevelDB which have pluggable comparator support, so you can decide how to
 * compare keys. But for NodeJS binding only default comparison algorithm is supported which
 * uses lexicographical comparison of the raw bytes of the keys
 *
 * It is important to use **helpers implemented here** to encode db keys so that key comparison properly work.
 */
export function encodeKey(bucket: number, key: Uint8Array | string | number | bigint): Uint8Array {
  let buf: Buffer;
  const prefixLength = BUCKET_LENGTH;
  //all keys are writen with prefixLength offet
  if (typeof key === "string") {
    buf = Buffer.alloc(key.length + prefixLength);
    buf.write(key, prefixLength);
  } else if (typeof key === "number" || typeof key === "bigint") {
    buf = Buffer.alloc(uintLen + prefixLength);
    buf.set(intToBytes(key, uintLen, "be"), prefixLength);
  } else {
    buf = Buffer.alloc(key.length + prefixLength);
    buf.set(key, prefixLength);
  }
  //bucket prefix on position 0
  buf.set(intToBytes(bucket, BUCKET_LENGTH, "le"), 0);
  return buf;
}

export function encodeNumberForDbKey(value: number, byteSize: number): Uint8Array {
  return intToBytes(value, byteSize, "be");
}

export function decodeNumberForDbKey(value: Uint8Array, byteSize: number): number {
  return bytesToInt(value.slice(0, byteSize), "be");
}

export function encodeStringForDbKey(value: string): Uint8Array {
  return Buffer.from(value, "utf-8");
}

export function decodeStringForDbKey(value: Uint8Array): string {
  return Buffer.from(value).toString("utf8");
}
